home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 25 / CU Amiga Magazine's Super CD-ROM 25 (1998)(EMAP Images)(GB)(Track 1 of 2)[!][issue 1998-08].iso / CUCD / Magazine / C_Tutorial / Part-13 / PatchLib / source / CommonFuncs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-12-10  |  26.1 KB  |  1,128 lines

  1. /*
  2. **    patch.library
  3. **
  4. **    Copyright © 1993-1997 by Stefan Fuchs
  5. **        Freely distributable.
  6. */
  7.  
  8. #ifndef _PATCH_INCLUDES_H
  9. #include "patch_includes.h"
  10. #endif
  11.  
  12. /****i* patch.library/FindPatchNotify ***************************************
  13. *
  14. *   NAME
  15. *        FindPatchNotify -- Find the notify structure with the given msgport.
  16. *
  17. *   SYNOPSIS
  18. *        node = FindPatchNotify( msgport )
  19. *
  20. *        struct Node *FindPatchNotify( struct MsgPort *);
  21. *
  22. *   FUNCTION
  23. *        Find the notify structure belonging to the given messageport.
  24. *
  25. *   INPUTS
  26. *        msgport = pointer to a message port
  27. *
  28. *   RESULT
  29. *        node = Pointer to the node with the given messageport or NULL, if
  30. *               not found.
  31. *
  32. *   NOTES
  33. *
  34. *   BUGS
  35. *
  36. *   SEE ALSO
  37. *
  38. ******************************************************************************
  39. *
  40. */
  41.  
  42. struct Node *FindPatchNotify( struct MsgPort *msgport)
  43. {
  44. struct Node *Pointer;
  45.  
  46.     for (Pointer = (struct Node *) (PatchBase->PB_NotifyListHeader.lh_Head);
  47.          Pointer->ln_Succ;
  48.          Pointer = (struct Node *)Pointer->ln_Succ)
  49.     {
  50.         if((struct MsgPort *)Pointer->ln_Name == msgport) return(Pointer);
  51.     }
  52.     return(NULL);
  53. }
  54.  
  55.  
  56. /****i* patch.library/SendNotify ***************************************
  57. *
  58. *   NAME
  59. *        SendNotify -- Send messages to all notify messageports
  60. *
  61. *   SYNOPSIS
  62. *        SendNotify( code, patch )
  63. *
  64. *        SendNotify( ULONG, struct Patch *);
  65. *
  66. *   FUNCTION
  67. *        Send PatchNotify messages to all notify messageports.
  68. *        The memory for the messages and a replyport will be allocated.
  69. *        This functions returns only, if all messages have been send back.
  70. *
  71. *   INPUTS
  72. *        code = PATCOD_xxx code indicating type of change (see patch.h)
  73. *        patch = optional pointer to patch structure
  74. *
  75. *   RESULT
  76. *
  77. *   NOTES
  78. *        If an error occurs (out of memory), no messages might be send.
  79. *
  80. *   BUGS
  81. *
  82. *   SEE ALSO
  83. *        AddPatchNotifyA(), patch.h
  84. *
  85. ******************************************************************************
  86. *
  87. */
  88.  
  89. void SendNotify( ULONG code, struct Patch *patch)
  90. {
  91. struct Node *pointer;
  92. struct PatchNotifyMessage *msg;
  93. struct MsgPort *port;
  94.  
  95.     if( msg = BAllocmem(sizeof(struct PatchNotifyMessage), MEMF_CLEAR| MEMF_PUBLIC))
  96.     {
  97.         if( port = CreateMsgPort())
  98.         {
  99.             msg->pnm_ExecMessage.mn_ReplyPort = port;
  100.             msg->pnm_ExecMessage.mn_Length = sizeof(struct PatchNotifyMessage);
  101.             msg->pnm_Class = PATCHNOTIFY_CLASS;
  102.             msg->pnm_Code = code;
  103.             msg->pnm_Object = patch;
  104.  
  105.             for (pointer = (struct Node *)PatchBase->PB_NotifyListHeader.lh_Head;
  106.                  pointer->ln_Succ;
  107.                  pointer = (struct Node *)pointer->ln_Succ)
  108.  
  109.             {
  110.                 PutMsg( (struct MsgPort *)(pointer->ln_Name), (struct Message *)msg);
  111.                 WaitPort( port);
  112.                 GetMsg( port);
  113.             }
  114.             DeleteMsgPort( port);
  115.         }
  116.         AFreemem( msg);
  117.     }
  118. }
  119. /****i* patch.library/GetMasterPatch ***************************************
  120. *
  121. *   NAME
  122. *        GetMasterPatch -- Return the MasterPatch structure a Patch structure
  123. *                          belongs to
  124. *
  125. *   SYNOPSIS
  126. *        master = GetMasterPatch( patch )
  127. *
  128. *        struct MasterPatch *GetMasterPatch( struct Patch *);
  129. *
  130. *   FUNCTION
  131. *        Return a pointer to the MasterPatch structure of a Patch structure.
  132. *
  133. *   INPUTS
  134. *        patch = pointer to a patch structure
  135. *
  136. *   RESULT
  137. *
  138. *   NOTES
  139. *
  140. *   BUGS
  141. *
  142. *   SEE ALSO
  143. *
  144. ******************************************************************************
  145. *
  146. */
  147.  
  148. struct MasterPatch *GetMasterPatch(struct Patch *patch)
  149. {
  150.     return( (struct MasterPatch *)(((UBYTE *)GetListNodeHeader( (struct Node *)patch)) -offsetof(struct MasterPatch, MPS_PatchHeader)));
  151. }
  152.  
  153.  
  154. /****i* patch.library/DisconnectStartType ***************************************
  155. *
  156. *   NAME
  157. *        DisconnectStartType -- Return a library's jumptable to its original state
  158. *
  159. *   SYNOPSIS
  160. *        error = DisconnectStartType( master )
  161. *
  162. *        ULONG error DisconnectStartType( struct MasterPatch *);
  163. *
  164. *   FUNCTION
  165. *        Return a library's jumptable to its original state and therefore
  166. *        no patch.library patchcodes will be called for this function.
  167. *        This function can fail, if a non-patch.library patch has been
  168. *        installed after our own one.
  169. *        This function will change the jump-table with Setfunction or
  170. *        an own replacement routine, depending on wether the patch
  171. *        was installed with SetFunction or not.
  172. *
  173. *   INPUTS
  174. *        master = pointer to a MasterPatch structure
  175. *
  176. *   RESULT
  177. *        error = errorcode as defined in patch.h
  178. *
  179. *   NOTES
  180. *
  181. *   BUGS
  182. *
  183. *   SEE ALSO
  184. *        patch.h, ConnectStartType()
  185. *
  186. ******************************************************************************
  187. *
  188. */
  189.  
  190.  
  191. #define INSTR_JMP   0x4ef9
  192.  
  193. ULONG DisconnectStartType( struct MasterPatch *master)
  194. {
  195. ULONG Result = PATERR_Ok;
  196. struct Patch *starttype;
  197. UBYTE *memptr;
  198.  
  199.     if( master->MPS_Flags & MPSF_Attached)
  200.     {
  201.         starttype = (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START);
  202.         if( master->MPS_Flags & MPSF_UseSetFunction)
  203.         {
  204.             Disable();
  205.             memptr = SetFunction( master->MPS_PatchedLibraryBase, master->MPS_PatchedLVO, master->MPS_SetFunctionResult);
  206.             if( memptr != &(starttype->PS_PatchCode->PC_PatchCodeStart))
  207.             {
  208.                 SetFunction( master->MPS_PatchedLibraryBase, master->MPS_PatchedLVO, (ULONG (*)())memptr);
  209.                 Result = PATERR_PatchInstalled;
  210.             }
  211.             Enable();
  212.         }
  213.         else
  214.         {
  215.             memptr = (UBYTE *)master->MPS_PatchedLibraryBase;
  216.             memptr += master->MPS_PatchedLVO;
  217.             Disable();
  218.             if( *((UWORD *)memptr) == INSTR_JMP)
  219.             {
  220.                 memptr += 2;
  221.                 if( ((ULONG *)memptr)[0] == (ULONG)(&(starttype->PS_PatchCode->PC_PatchCodeStart)))
  222.                 {
  223.                     *((ULONG *)memptr) = master->MPS_OldEntry02;
  224.                     memptr -= 2;
  225.                     *((UWORD *)memptr) = master->MPS_OldEntry01;
  226.                     CacheClearU();
  227.                     master->MPS_PatchedLibraryBase->lib_Flags |= LIBF_CHANGED;
  228.                     SumLibrary(master->MPS_PatchedLibraryBase);
  229.                 }
  230.                 else Result = PATERR_PatchInstalled;
  231.             }
  232.             else Result = PATERR_PatchInstalled;
  233.             Enable();
  234.         }
  235.         if( Result == PATERR_Ok)
  236.             master->MPS_Flags &= ~MPSF_Attached;
  237.     }
  238.     return(Result);
  239. }
  240.  
  241.  
  242. /****i* patch.library/ConnectStartType ***************************************
  243. *
  244. *   NAME
  245. *        ConnectStartType -- Change a library's jump-table, to point to
  246. *                            the StartType patchcode
  247. *
  248. *   SYNOPSIS
  249. *        error = ConnectStartType( master )
  250. *
  251. *        ULONG error ConnectStartType( struct MasterPatch *);
  252. *
  253. *   FUNCTION
  254. *        Change a library's jump-table, to point to the StartType patchcode.
  255. *
  256. *        This function can fail, if the jump-table entry is not in the standard
  257. *        format.
  258. *        This function will change the jump-table with Setfunction or
  259. *        an own replacement routine, depending on wether PatchSetFunc is
  260. *        active or not.
  261. *
  262. *   INPUTS
  263. *        master = pointer to a MasterPatch structure
  264. *
  265. *   RESULT
  266. *        error = errorcode as defined in patch.h
  267. *
  268. *   NOTES
  269. *
  270. *   BUGS
  271. *
  272. *   SEE ALSO
  273. *        patch.h, DisconnectStartType()
  274. *
  275. ******************************************************************************
  276. *
  277. */
  278.  
  279.  
  280. ULONG ConnectStartType( struct MasterPatch *master)
  281. {
  282. ULONG Result = PATERR_Ok;
  283. struct Patch *starttype;
  284. UBYTE *memptr;
  285.  
  286.     if( (master->MPS_Flags & MPSF_Attached) == NULL)
  287.     {
  288.         if( master->MPS_PatchedLibraryBase)
  289.         {
  290.             Result = FillOrigType(master);
  291.             if( Result == PATERR_Ok)
  292.             {
  293.                 if(starttype = (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_START))
  294.                 {
  295.                     master->MPS_Flags |= MPSF_Attached;
  296.                     if( master->MPS_Flags & MPSF_UseSetFunction)
  297.                     {
  298.                         master->MPS_SetFunctionResult = SetFunction( master->MPS_PatchedLibraryBase, master->MPS_PatchedLVO, (ULONG (*)())&(starttype->PS_PatchCode->PC_PatchCodeStart));
  299.                     }
  300.                     else
  301.                     {
  302.                         memptr = (UBYTE *)master->MPS_PatchedLibraryBase;
  303.                         memptr += master->MPS_PatchedLVO;
  304.                         Disable();
  305.                         *((UWORD *)memptr) = INSTR_JMP;
  306.                         memptr += 2;
  307.                         *((ULONG *)memptr) = (ULONG)&(starttype->PS_PatchCode->PC_PatchCodeStart);
  308.                         CacheClearU();
  309.                         master->MPS_PatchedLibraryBase->lib_Flags |= LIBF_CHANGED;
  310.                         SumLibrary(master->MPS_PatchedLibraryBase);
  311.                         Enable();
  312.                     }
  313.                 }
  314.             }
  315.         }
  316.     }
  317.     return( Result);
  318. }
  319.  
  320.  
  321. /****i* patch.library/FillOrigType ***************************************
  322. *
  323. *   NAME
  324. *        FillOrigType -- Set certain parameters for OrigType patch structures
  325. *
  326. *   SYNOPSIS
  327. *        error = FillOrigType( master )
  328. *
  329. *        ULONG error FillOrigType( struct MasterPatch *);
  330. *
  331. *   FUNCTION
  332. *        Read the from the library's jump-table and check, if it is in a format
  333. *        patch.library understands.
  334. *        Check, if PatchSetFunc is running and set the appropriate flags.
  335. *        This function can fail, if the jump-table entry is not in the standard
  336. *        format.
  337. *
  338. *   INPUTS
  339. *        master = pointer to a MasterPatch structure
  340. *
  341. *   RESULT
  342. *        error = errorcode as defined in patch.h
  343. *
  344. *   NOTES
  345. *
  346. *   BUGS
  347. *
  348. *   SEE ALSO
  349. *        patch.h, ConnectStartType()
  350. *
  351. ******************************************************************************
  352. *
  353. */
  354. ULONG FillOrigType( struct MasterPatch *master)
  355. {
  356. struct TagItem taglist[2] =
  357.     { {PATT_PatchName, (ULONG) ("PatchSetFunc")},
  358.       TAG_DONE
  359.     };
  360. struct Patch *origtype;
  361. UBYTE *memptr;
  362.  
  363.     memptr = (UBYTE *)master->MPS_PatchedLibraryBase;
  364.     memptr += master->MPS_PatchedLVO;
  365.  
  366.     Disable();
  367.     master->MPS_OldEntry01 = *((UWORD *)memptr);
  368.     memptr += 2;
  369.     master->MPS_OldEntry02 = *((ULONG *)memptr);
  370.     Enable();
  371.  
  372.     origtype = (struct Patch *)FindType( (struct List *)&(master->MPS_PatchHeader), PS_TYPE_ORIG);
  373.  
  374.     if( master->MPS_OldEntry01 != INSTR_JMP)
  375.         return(PATERR_FuncNotStd);
  376.  
  377.     memptr = origtype->PS_Jsr;
  378.     memptr += 2;
  379.     *((ULONG *)memptr) = master->MPS_OldEntry02;
  380.  
  381.     if( PatchBase->PB_Flags & PBF_PatchSetFuncActive)
  382.         return(PATERR_Ok);
  383.  
  384.     if( FindPatchTagsA( taglist))
  385.         return(PATERR_Ok);
  386.  
  387.     master->MPS_Flags |= MPSF_UseSetFunction;
  388.     return(PATERR_Ok);
  389. }
  390.  
  391. /****i* patch.library/TestUsage ***************************************
  392. *
  393. *   NAME
  394. *        TestUsage -- Test, if a patchcode is in use by any task
  395. *
  396. *   SYNOPSIS
  397. *        error = TestUsage( patch )
  398. *
  399. *        ULONG error TestUsage( struct Patch *);
  400. *
  401. *   FUNCTION
  402. *        Test, if a patchcode is in use by any task.
  403. *        If the global CheckPC flag is turned off, only test the usage counters,
  404. *        otherwise also check all tasks and compare their program-counters
  405. *        against specific memory locations not covered by the usage-counters.
  406. *        Skip these tests for certain OS-functions.
  407. *
  408. *   INPUTS
  409. *        patch = pointer to a Patch structure or NULL for no action.
  410. *
  411. *   RESULT
  412. *        error = errorcode as defined in patch.h
  413. *
  414. *   NOTES
  415. *
  416. *   BUGS
  417. *
  418. *   SEE ALSO
  419. *
  420. ******************************************************************************
  421. *
  422. */
  423.  
  424. #define LVORemTask -288
  425. #define LVOExit -144
  426.  
  427.  
  428. ULONG TestUsage( struct Patch *patch)
  429. {
  430. struct MasterPatch *master;
  431. struct Task *task;
  432.  
  433.     if( patch)
  434.     {
  435.         master = GetMasterPatch( patch);
  436.  
  437. /* exec/Remtask(0) does not return from rts, so ignore invalid UsageCounter */
  438.         if( (master->MPS_PatchedLVO == LVORemTask) && strcmp( "exec.library", master->MPS_Node.ln_Name) == NULL)
  439.             return( PATERR_Ok);
  440.  
  441. /* dos/Exit(0) does not return from rts, so ignore invalid UsageCounter */
  442.         if( (master->MPS_PatchedLVO == LVOExit) && strcmp( "dos.library", master->MPS_Node.ln_Name) == NULL)
  443.             return( PATERR_Ok);
  444.         if( patch->PS_PatchCode->PC_Usage)
  445.         {
  446.             return(PATERR_PatchInUse);
  447.         }
  448.         if( PatchBase->PB_Flags & PBF_CheckPC == NULL)
  449.             return(PATERR_Ok);
  450.  
  451.         Disable();
  452.         for (task = (struct Task *) (SysBase->TaskReady.lh_Head);
  453.              task->tc_Node.ln_Succ;
  454.              task = (struct Task *)task->tc_Node.ln_Succ)
  455.         {
  456.             if(TestPCUsage( patch, GetPC( task->tc_SPReg, SysBase)))
  457.             {
  458.                 Enable();
  459.                 return(PATERR_PatchInUse);
  460.             }
  461.         }
  462.  
  463.         for (task = (struct Task *) (SysBase->TaskWait.lh_Head);
  464.              task->tc_Node.ln_Succ;
  465.              task = (struct Task *)task->tc_Node.ln_Succ)
  466.         {
  467.             if(TestPCUsage( patch, GetPC( task->tc_SPReg, SysBase)))
  468.             {
  469.                 Enable();
  470.                 return(PATERR_PatchInUse);
  471.             }
  472.         }
  473.         Enable();
  474.     }
  475.     return(PATERR_Ok);
  476. }
  477.  
  478.  
  479. /****i* patch.library/TestPCUsage ***************************************
  480. *
  481. *   NAME
  482. *        TestPCUsage -- Compare certain memory adresses against a PC
  483. *
  484. *   SYNOPSIS
  485. *        error = TestPCUsage( patch, PC)
  486. *
  487. *        ULONG error TestPCUsage( struct Patch *, APTR);
  488. *
  489. *   FUNCTION
  490. *        Compare certain memory adresses against a programm-counter.
  491. *
  492. *   INPUTS
  493. *        patch = pointer to a Patch structure.
  494. *        PC = pointer to the next instruction, to be executed.
  495. *
  496. *   RESULT
  497. *        error = 0: Code is not in use
  498. *                1: Code is in use
  499. *
  500. *   NOTES
  501. *
  502. *   BUGS
  503. *
  504. *   SEE ALSO
  505. *
  506. ******************************************************************************
  507. *
  508. */
  509.  
  510. ULONG TestPCUsage( struct Patch *patch, APTR pc)
  511. {
  512.     if(patch->PS_TestUsage1 == pc)
  513.         return 1;
  514.     if(patch->PS_TestUsage2 == pc)
  515.         return 1;
  516.     if(patch->PS_TestUsage3 == pc)
  517.         return 1;
  518.     return 0;
  519. }
  520.  
  521.  
  522. /****i* patch.library/ReCalcStackSize ***************************************
  523. *
  524. *   NAME
  525. *        ReCalcStackSize -- Calculate the highest required stacksize
  526. *
  527. *   SYNOPSIS
  528. *        ReCalcStackSize( master)
  529. *
  530. *        ReCalcStackSize( struct  MasterPatch *);
  531. *
  532. *   FUNCTION
  533. *        Calculate the highest required stacksize for all patches and
  534. *        place it, into the StartTypes stack fieled
  535. *        If the stacksize has changed, allocate memory for stack caching.
  536. *
  537. *   INPUTS
  538. *        master = pointer to a MasterPatch structure.
  539. *
  540. *   RESULT
  541. *
  542. *   NOTES
  543. *
  544. *   BUGS
  545. *
  546. *   SEE ALSO
  547. *
  548. ******************************************************************************
  549. *
  550. */
  551.  
  552. void ReCalcStackSize( struct MasterPatch *master)
  553. {
  554. ULONG StackSize = 0;
  555. struct Patch *patch;
  556.  
  557.     for( patch = (struct Patch *)master->MPS_PatchHeader.mlh_Head;
  558.          patch->PS_Node.ln_Succ;
  559.             patch= (struct Patch *)patch->PS_Node.ln_Succ)
  560.     {
  561.         if(( patch->PS_Node.ln_Type == PS_TYPE_USER) || ( patch->PS_Node.ln_Type == PS_TYPE_SYSTEM) || ( patch->PS_Node.ln_Type == PS_TYPE_ORIG))
  562.         {
  563.             if( patch->PS_StackSize > StackSize)
  564.                 StackSize = patch->PS_StackSize;
  565.         }
  566.     }
  567.  
  568.     patch= (struct Patch *)FindType( (struct List *)(&(master->MPS_PatchHeader)), PS_TYPE_START);
  569.     if(patch->PS_PatchCode->PC_StackSize != StackSize)
  570.     {
  571.         patch->PS_PatchCode->PC_StackSize = StackSize;
  572.         PreAllocatedStacksAlloc( master, StackSize );
  573.     }
  574. }
  575.  
  576. /****i* patch.library/PreAllocatedStacksAlloc ***************************************
  577. *
  578. *   NAME
  579. *        PreAllocatedStacksAlloc -- Allocate memory for stack extension
  580. *
  581. *   SYNOPSIS
  582. *        PreAllocatedStacksAlloc( master, stacksize)
  583. *
  584. *        PreAllocatedStacksAlloc( struct  MasterPatch *, ULONG);
  585. *
  586. *   FUNCTION
  587. *        Allocate memory for stack extension of the given stacksize and
  588. *        fill the slots in the masterpatch structure.
  589. *        A stacksize, of null frees all slots.
  590. *
  591. *   INPUTS
  592. *        master = pointer to a MasterPatch structure.
  593. *    stacksize = number of bytes to allocate
  594. *
  595. *   RESULT
  596. *
  597. *   NOTES
  598. *
  599. *   BUGS
  600. *
  601. *   SEE ALSO
  602. *
  603. ******************************************************************************
  604. *
  605. */
  606.  
  607. void PreAllocatedStacksAlloc( struct MasterPatch *master, ULONG stacksize)
  608. {
  609. ULONG stacks, i;
  610.  
  611.     PreAllocatedStacksFree( master);
  612.  
  613.     if(stacksize)
  614.     {
  615.         stacks = MIN(STACKSLOTS,PatchBase->PB_StackExtensions);
  616.         if( stacks)
  617.         {
  618.             for( i = 0; i < stacks; i++)
  619.             {
  620.                 master->MPS_StackSlots[i] = AllocStack(stacksize);
  621.             }
  622.         }
  623.     }
  624. }
  625. /****i* patch.library/PreAllocateStacksFree ***************************************
  626. *
  627. *   NAME
  628. *        PreAllocatedStacksFree -- Free memory for stack extension
  629. *
  630. *   SYNOPSIS
  631. *        PreAllocatedStacksFree( master)
  632. *
  633. *        PreAllocatedStacksFree( struct  MasterPatch *);
  634. *
  635. *   FUNCTION
  636. *        Free memory for stack extension
  637. *        
  638. *
  639. *   INPUTS
  640. *        master = pointer to a MasterPatch structure.
  641. *
  642. *   RESULT
  643. *
  644. *   NOTES
  645. *
  646. *   BUGS
  647. *
  648. *   SEE ALSO
  649. *
  650. ******************************************************************************
  651. *
  652. */
  653.  
  654. void PreAllocatedStacksFree( struct MasterPatch *master)
  655. {
  656. ULONG i;
  657. struct PatchStack *patchstack;
  658.  
  659.     for( i = 0; i < STACKSLOTS; i++)
  660.     {
  661.         patchstack = master->MPS_StackSlots[i];
  662.         master->MPS_StackSlots[i] = 0;
  663.         FreeStack( patchstack );
  664.     }
  665. }
  666.  
  667. /****i* patch.library/AllocStack ***************************************
  668. *
  669. *   NAME
  670. *        AllocStack -- Allocate and initialize a new stack
  671. *
  672. *   SYNOPSIS
  673. *        patchstack = AllocStack( stacksize )
  674. *
  675. *        APTR AllocStack( ULONG);
  676. *
  677. *   FUNCTION
  678. *        Allocate memory for stack extension
  679. *        
  680. *
  681. *   INPUTS
  682. *        stacksize = number of bytes, the new stack should hold.
  683. *
  684. *   RESULT
  685. *    patchstack = pointer to a PatchStack structure or NULL on failure.
  686. *
  687. *   NOTES
  688. *
  689. *   BUGS
  690. *
  691. *   SEE ALSO
  692. *
  693. ******************************************************************************
  694. *
  695. */
  696.  
  697. struct PatchStack *AllocStack( ULONG stacksize )
  698. {
  699. APTR stack;
  700. struct PatchStack *patchstack = NULL;
  701.  
  702.     stack = AllocVec(stacksize + sizeof(struct PatchStack) + 8, MEMF_PUBLIC);
  703.     if(stack )
  704.     {
  705.         patchstack = (struct PatchStack *)((UBYTE *)stack + stacksize);
  706.         patchstack->PST_Reserved2 = 0xCCDDEEFF;
  707.         patchstack->PST_Reserved1 = 0x8899AABB;
  708.  
  709.         patchstack->PST_StackSwap.stk_Upper = (ULONG) patchstack;
  710.         patchstack->PST_StackSwap.stk_Lower = stack;
  711.  
  712.         patchstack->PST_Usage = 0L;
  713.         patchstack->PST_Stacksize = stacksize;
  714.         patchstack->PST_Magic2 = &patchstack->PST_Magic1;
  715.         patchstack->PST_Magic1 = 0x50415443;   /* 'PATC' */
  716.     }
  717.     return( patchstack);
  718. }
  719. /****i* patch.library/FreeStack ***************************************
  720. *
  721. *   NAME
  722. *        FreeStack -- Free memory for stack 
  723. *
  724. *   SYNOPSIS
  725. *        FreeStack( patchstack)
  726. *
  727. *        FreeStack( APTR );
  728. *
  729. *   FUNCTION
  730. *        Free memory for stack extension
  731. *        
  732. *
  733. *   INPUTS
  734. *        patchstack = pointer to a PatchStack structure or NULL for no action.
  735. *
  736. *   RESULT
  737. *
  738. *   NOTES
  739. *
  740. *   BUGS
  741. *
  742. *   SEE ALSO
  743. *
  744. ******************************************************************************
  745. *
  746. */
  747.  
  748. void FreeStack( struct PatchStack *patchstack )
  749. {
  750.     if( patchstack)
  751.     {
  752.         patchstack->PST_Magic1 = 0;
  753.         patchstack->PST_Magic2 = NULL;
  754.         patchstack = (struct PatchStack *)((UBYTE *)patchstack - patchstack->PST_Stacksize);
  755.         FreeVec(patchstack);
  756.     }
  757. }
  758. /****i* patch.library/AllocStackCached ***************************************
  759. *
  760. *   NAME
  761. *        AllocStackCached -- Allocate and initialize a new stack
  762. *
  763. *   SYNOPSIS
  764. *        patchstack = AllocStackCached( patch, stacksize )
  765. *
  766. *        APTR AllocStackCached( struct Patch *, ULONG );
  767. *        D0                     A0              D0
  768. *
  769. *
  770. *   FUNCTION
  771. *        Allocate memory for stack extension
  772. *        
  773. *
  774. *   INPUTS
  775. *        patch = patch structure to allocate stack for a stack.
  776. *        stacksize = number of bytes, the new stack should hold.
  777. *
  778. *   RESULT
  779. *    patchstack = pointer to PatchStack structure or NULL on failure.
  780. *
  781. *   NOTES
  782. *        This function must be optimized for speed and stack-usage,
  783. *        as it may be called from patch routines.
  784. *
  785. *   BUGS
  786. *
  787. *   SEE ALSO
  788. *
  789. ******************************************************************************
  790. *
  791. */
  792.  
  793. struct PatchStack * LIBFUNC AllocStackCached( REGA0 struct Patch *patch GNUC_REGA0, REGD0 ULONG stacksize GNUC_REGD0)
  794. {
  795. ULONG i, stacks;
  796. struct MasterPatch *master;
  797.  
  798.     stacks = MIN(STACKSLOTS,PatchBase->PB_StackExtensions);
  799.     if( stacks)
  800.     {
  801.         master = GetMasterPatch( patch);
  802.         for( i = 0; i < stacks; i++)
  803.         {
  804.             if(master->MPS_StackSlots[i])
  805.             {
  806.                 if(master->MPS_StackSlots[i]->PST_Usage == NULL)
  807.                 {
  808.                     Disable();
  809.                     master->MPS_StackSlots[i]->PST_Usage = 1L; /* atomic */
  810.                     Enable();
  811.                     return(master->MPS_StackSlots[i]);
  812.                 }
  813.             }
  814.         }
  815.     }
  816.     if(PatchBase->PB_Flags & PBF_NoStackAllocmem)
  817.     {
  818.         return(NULL);
  819.     }
  820.  
  821.     return( AllocStack(stacksize));
  822. }
  823. /****i* patch.library/FreeStackCached ***************************************
  824. *
  825. *   NAME
  826. *        FreeStackCached -- Free memory for stack 
  827. *
  828. *   SYNOPSIS
  829. *        FreeStackCached( patchstack)
  830. *
  831. *        FreeStackCached( APTR );
  832. *                         a1
  833. *
  834. *   FUNCTION
  835. *        Free memory for stack extension
  836. *        
  837. *
  838. *   INPUTS
  839. *        patchstack = pointer to PatchStack structure or NULL for no action.
  840. *
  841. *   RESULT
  842. *
  843. *   NOTES
  844. *        This function must be optimized for speed and stack-usage,
  845. *        as it may be called from patch routines.
  846. *
  847. *   BUGS
  848. *
  849. *   SEE ALSO
  850. *
  851. ******************************************************************************
  852. *
  853. */
  854.  
  855. void LIBFUNC FreeStackCached( REGA1 struct PatchStack *patchstack GNUC_REGA1)
  856. {
  857.     if(patchstack->PST_Usage)
  858.     {
  859.         Disable();
  860.         patchstack->PST_Usage = 0L;    /* atomic */
  861.         Enable();
  862.     }
  863.     else
  864.     {
  865.         FreeStack( patchstack);
  866.     }
  867. }
  868.  
  869. /****i* patch.library/PatchMatch ***************************************
  870. *
  871. *   NAME
  872. *        PatchMatch -- Check, if a task is allowed to execute a patch
  873. *
  874. *   SYNOPSIS
  875. *        success = PatchMatch( tasklistheader)
  876. *
  877. *        ULONG PatchMatch( struct TLHeader *);
  878. *        D0                A0
  879. *
  880. *   FUNCTION
  881. *        Check, if a task is allowed to execute a patch
  882. *
  883. *   INPUTS
  884. *        tasklistheader = pointer to TLHeader structure.
  885. *
  886. *   RESULT
  887. *        success = 
  888. *
  889. *
  890. *   NOTES
  891. *        This function must be optimized for speed and stack-usage,
  892. *        as it may be called from patch routines.
  893. *
  894. *   BUGS
  895. *
  896. *   SEE ALSO
  897. *
  898. ******************************************************************************
  899. *
  900. */
  901.  
  902. ULONG LIBFUNC PatchMatch( REGA0 struct TLHeader *list GNUC_REGA0)
  903. {
  904. struct Task *task;
  905. struct TLNode *pointer;
  906.  
  907.     task = SysBase->ThisTask;
  908.  
  909.     for (pointer = (struct TLNode *) list->TL_List.lh_Head;
  910.          pointer->TN_Node.ln_Succ;
  911.          pointer = (struct TLNode *)pointer->TN_Node.ln_Succ)
  912.     {
  913.  
  914.         switch( pointer->TN_Node.ln_Type)
  915.         {
  916.             case TLI_TYPE_TASKID:
  917.                 if(task == (struct Task *)pointer->TN_Node.ln_Name)
  918.                 {
  919.                     return(list->TL_Result1);
  920.                 }
  921.                 break;
  922.  
  923.             case TLI_TYPE_TASKNAME:
  924.                 if( strcmp(task->tc_Node.ln_Name, pointer->TN_Node.ln_Name) == 0)
  925.                 {
  926.                     return(list->TL_Result1);
  927.                 }
  928.                 break;
  929.  
  930.             case TLI_TYPE_TASKPATTERN:
  931.                 if( MatchPatternNoCase( pointer->TN_Pattern, task->tc_Node.ln_Name))
  932.                 {
  933.                     return(list->TL_Result1);
  934.                 }
  935.                 break;
  936.         }
  937.     }
  938.  
  939.     return(list->TL_Result2);
  940. }
  941.  
  942.  
  943. /****i* patch.library/SAVEObtainSemaphoreShared ***************************************
  944. *
  945. *   NAME
  946. *        SAVEObtainSemaphoreShared -- Safely get shared access to the global semaphore
  947. *
  948. *   SYNOPSIS
  949. *        error = SAVEObtainSemaphoreShared( )
  950. *
  951. *        ULONG error SAVEObtainSemaphoreShared( void);
  952. *
  953. *   FUNCTION
  954. *        Get shared access to the global patch.library semaphore without
  955. *        breaking forbid() or disable() unless the global BreakForbid flag
  956. *        has been set.
  957. *
  958. *   INPUTS
  959. *
  960. *   RESULT
  961. *        error = errorcode as defined in patch.h
  962. *
  963. *   NOTES
  964. *        On V38 or less this function returns an exclusive semaphore.
  965. *
  966. *   BUGS
  967. *
  968. *   SEE ALSO
  969. *        SAVEObtainSemaphore(), patch.h
  970. *
  971. ******************************************************************************
  972. *
  973. */
  974.  
  975. ULONG SAVEObtainSemaphoreShared( void)
  976. {
  977.     if(SysBase->LibNode.lib_Version < 39L)
  978.     {
  979.         return(SAVEObtainSemaphore());
  980.     }
  981.  
  982.     if( (SysBase->IDNestCnt == -1 && SysBase->TDNestCnt == -1) ||
  983.             (PatchBase->PB_Flags & PBF_BreakForbid))
  984.         ObtainSemaphoreShared(&(PatchBase->PB_Semaphore));
  985.     else
  986.     {
  987.         if( AttemptSemaphoreShared(&(PatchBase->PB_Semaphore)) == FALSE)
  988.             return( PATERR_NoSemaphore);
  989.     }
  990.     return(PATERR_Ok);
  991. }
  992.  
  993. /****i* patch.library/SAVEObtainSemaphore ***************************************
  994. *
  995. *   NAME
  996. *        SAVEObtainSemaphore -- Safely get access to the global semaphore
  997. *
  998. *   SYNOPSIS
  999. *        error = SAVEObtainSemaphore( )
  1000. *
  1001. *        ULONG error SAVEObtainSemaphore( void);
  1002. *
  1003. *   FUNCTION
  1004. *        Get access to the global patch.library semaphore without
  1005. *        breaking forbid() or disable() unless the global BreakForbid flag
  1006. *        has been set.
  1007. *
  1008. *   INPUTS
  1009. *
  1010. *   RESULT
  1011. *        error = errorcode as defined in patch.h
  1012. *
  1013. *   NOTES
  1014. *
  1015. *   BUGS
  1016. *
  1017. *   SEE ALSO
  1018. *        SAVEObtainSemaphoreShared(), patch.h
  1019. *
  1020. ******************************************************************************
  1021. *
  1022. */
  1023.  
  1024. ULONG SAVEObtainSemaphore( void)
  1025. {
  1026.     if( (SysBase->IDNestCnt == -1 && SysBase->TDNestCnt == -1) || (PatchBase->PB_Flags & PBF_BreakForbid))
  1027.         ObtainSemaphore(&(PatchBase->PB_Semaphore));
  1028.     else
  1029.     {
  1030.         if( AttemptSemaphore(&(PatchBase->PB_Semaphore)) == FALSE)
  1031.             return( PATERR_NoSemaphore);
  1032.     }
  1033.     return(PATERR_Ok);
  1034. }
  1035.  
  1036. /****i* patch.library/TestPatchHandle ***************************************
  1037. *
  1038. *   NAME
  1039. *        TestPatchHandle -- Test, if a pointer to a patch structure is valid.
  1040. *
  1041. *   SYNOPSIS
  1042. *        error = TestPatchHandle( patch)
  1043. *
  1044. *        ULONG error TestPatchHandle( struct Patch *);
  1045. *
  1046. *   FUNCTION
  1047. *        Test, if a pointer to a patch structure is still valid.
  1048. *
  1049. *   INPUTS
  1050. *        patch = pointer to a (hopefully) valid patch structure or NULL
  1051. *                for no action.
  1052. *
  1053. *   RESULT
  1054. *        error = errorcode as defined in patch.h
  1055. *
  1056. *   NOTES
  1057. *
  1058. *   BUGS
  1059. *
  1060. *   SEE ALSO
  1061. *        patch.h
  1062. *
  1063. ******************************************************************************
  1064. *
  1065. */
  1066. ULONG TestPatchHandle( struct Patch *patch)
  1067. {
  1068. struct MasterPatch *master;
  1069. struct Node *pointer;
  1070.     if( patch)
  1071.     {
  1072.         for( master = (struct MasterPatch *)(&(PatchBase->PB_MasterPatchHeader))->lh_Head;
  1073.              master->MPS_Node.ln_Succ;
  1074.              master = (struct MasterPatch *)master->MPS_Node.ln_Succ)
  1075.         {
  1076.             for( pointer = (struct Node *)(&(master->MPS_PatchHeader))->mlh_Head;
  1077.                  pointer->ln_Succ;
  1078.                  pointer = (struct Node *)pointer->ln_Succ)
  1079.             {
  1080.                 if( pointer == (struct Node *)patch) return(PATERR_Ok);
  1081.             }
  1082.         }
  1083.     }
  1084.     return( PATERR_InvalidHandle);
  1085. }
  1086.  
  1087. /****i* patch.library/BAllocmem ***************************************
  1088. *
  1089. *   NAME
  1090. *        BAllocmem -- Allocate memory from the memory pool remembering
  1091. *                     its size.
  1092. *
  1093. *   SYNOPSIS
  1094. *        memory = BAllocmem( size, attributes )
  1095. *
  1096. *        APTR BAllocmem( ULONG, ULONG );
  1097. *
  1098. *   FUNCTION
  1099. *        Allocate memory from the global or (if it exists) from a local
  1100. *        memory pool and remember its size.
  1101. *        Deallocate this memory with AFreemem().
  1102. *
  1103. *   INPUTS
  1104. *        size = number of bytes to allocate
  1105. *        attributes = memory attributes (only required, if no local
  1106. *                     memory pool is available)
  1107. *
  1108. *   RESULT
  1109. *        memory = pointer to newly allocated memory block or NULL on failure
  1110. *
  1111. *   NOTES
  1112. *
  1113. *   BUGS
  1114. *
  1115. *   SEE ALSO
  1116. *        Allocmem(), AllocVec(), AFreemem()
  1117. *
  1118. ******************************************************************************
  1119. *
  1120. */
  1121.  
  1122.  
  1123. APTR BAllocmem( ULONG size, ULONG attr)
  1124. {
  1125.     return( AAllocmem( size, attr, PatchBase->PB_MemoryPool));
  1126. }
  1127.  
  1128.